// 如何区分堆区和栈区
// 在C++中，堆区和栈区是两种主要的内存分配区域，它们有着根本性的区别。下面我将从多个角度详细解释如何区分这两个区域。

// 1. 分配方式
// 栈区：
// 自动分配和释放，由编译器管理
// 函数调用时创建，函数返回时销毁
// 使用LIFO（后进先出）的数据结构

// 堆区：
// 手动分配和释放，由程序员管理
// 显式分配（使用new/malloc），显式释放（使用delete/free）
// 随机存取，没有特定的分配模式

// 2. 代码层面的区分
// 栈区变量：
void function()
{
    int x;           // 栈上的基本类型
    double y = 3.14; // 栈上的基本类型
    MyClass obj;     // 栈上的对象
    int array[10];   // 栈上的数组
} // 函数结束时，所有栈变量自动销毁

// 堆区变量：
void function()
{
    int *px = new int;             // 堆上的整数
    double *py = new double(3.14); // 堆上的double
    MyClass *pobj = new MyClass;   // 堆上的对象
    int *parray = new int[10];     // 堆上的数组

    // 必须手动释放，否则内存泄漏
    delete px;
    delete py;
    delete pobj;
    delete[] parray;
}

// 3. 生命周期
// 栈区：
// 生命周期与其所在的作用域绑定
// 离开作用域时自动销毁

// 堆区：
// 生命周期由程序员控制
// 从new/malloc开始，到delete/free结束
// 如果不手动释放，会一直存在直到程序结束（造成内存泄漏）

// 4. 大小限制
// 栈区：
// 大小通常有限（取决于操作系统和编译器设置，通常为几MB）
// 分配大量内存可能导致栈溢出

// 堆区：
// 大小受限于系统的虚拟内存，通常比栈大得多
// 适合分配大量或大型对象

// 5. 性能特点
// 栈区：
// 分配和释放速度快（简单的指针移动）
// 内存连续，访问效率高
// 没有内存碎片问题

// 堆区：
// 分配和释放速度相对较慢（需要内存管理算法）
// 可能产生内存碎片
// 访问速度相对较慢（指针间接访问）

// 6. 智能指针的角色
// 现代C++中，我们通常使用智能指针来管理堆内存：
void modernFunction()
{
    // 堆上分配，但由智能指针管理生命周期
    std::unique_ptr<int> px = std::make_unique<int>(42);
    std::shared_ptr<MyClass> pobj = std::make_shared<MyClass>();

    // 不需要手动delete，智能指针会处理
} // 智能指针离开作用域时自动释放堆内存

// 7. 实际判断方法
// 如何在代码中判断一个对象是在栈上还是堆上？
// 1. 关键字判断：
// 使用了new/malloc的对象在堆上
// 没有使用这些关键字的局部变量在栈上
// 2. 地址范围（不可靠，仅供参考）：
// 栈区地址通常在高地址区域
// 堆区地址通常在低地址区域
// 但这取决于具体的操作系统和编译器实现

// 总结
// 区分堆区和栈区的关键点：

// 栈区变量自动分配和释放，堆区需要手动管理
// 栈区使用int x这样的直接声明，堆区使用new/malloc
// 栈区大小有限但速度快，堆区大小更大但速度较慢
// 栈区变量生命周期与作用域绑定，堆区变量生命周期由程序员控制
// 现代C++中，优先使用智能指针来管理堆内存，避免手动内存管理的错误

// **线程与堆内存共享
// 在C++程序中，所有线程默认共享同一块堆区内存。这是多线程编程中的一个重要特性，同时也是需要特别注意的地方。

// 内存共享模型
// 在典型的C++多线程程序中：

// 堆内存（Heap）：
// 所有线程共享同一个堆
// 任何线程都可以分配堆内存
// 任何线程都可以访问和修改其他线程分配的堆内存
// 这种共享是无条件的，不需要特殊设置

// 栈内存（Stack）：
// 每个线程有自己独立的栈
// 一个线程不能直接访问另一个线程的栈内存
// 线程的栈大小通常在线程创建时确定

// 全局/静态变量：
// 也是所有线程共享的
// 存储在程序的数据段，不在堆或栈上

// 堆共享的影响
// 堆内存共享带来的影响：

// 优势
// 线程间可以方便地共享数据
// 一个线程可以分配内存，另一个线程可以释放它
// 便于实现复杂的数据交换和共享数据结构

// 挑战
// 并发访问问题：多个线程同时修改同一块堆内存可能导致数据竞争
// 同步需求：需要使用互斥锁、条件变量等同步机制保护共享数据
// 内存管理复杂性：一个线程分配的内存，可能需要在另一个线程中释放